#!/usr/bin/python
# author dennis
# 2022年06月16日
import socket
import select
import sys


def tcp_server():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    addr = ('', 2000)
    s.bind(addr)  # 绑定，端口没有激活
    s.listen(128)  # listen时，listen里的数字表示同一时刻能连接客户端的程度
    # 接收一个客户端的连接请求，并返回一个新的套接字
    epoll = select.epoll()  # 创建一个epoll对象
    # 让epoll监控s, sys.stdin
    epoll.register(s.fileno(), select.EPOLLIN)
    epoll.register(sys.stdin.fileno(), select.EPOLLIN)
    client_list = []
    while True:
        # 谁的缓冲区有数据，就填写到events,events是列表里边存的是元组，（fd,事件）
        # 当文件句柄发生变化，会以列表的形式报告进程
        events = epoll.poll(-1)
        for fd, event in events:
            if fd == s.fileno():
                # 有客户端连接，就连上，得到客户端new_client，放入列表，注册它
                # 不同于以上socket()返回的用于监听和接收客户请求的套接字，与此客户端通信是通过新的套接字上来完成
                new_client, client_addr = s.accept()
                print(client_addr)
                client_list.append(new_client)
                epoll.register(new_client.fileno(), select.EPOLLIN)
            else:
                remove_client = None
                for client in client_list:  # 遍历所有的客户端对象
                    if client.fileno() == fd:
                        # 一旦对端断开，recv不会卡住，会返回空
                        data = client.recv(1000)  # 接收对应客户端发过来数据,假如data没有数据，为空，不会卡住
                        if data:  # 拿到数据，群发给其他的客户端
                            for other_client in client_list:
                                if other_client is client:
                                    pass
                                else:
                                    other_client.send(data)
                        else:  # 断开了就记录一下
                            remove_client = client
                if remove_client:
                    client_list.remove(remove_client)
                    epoll.unregister(remove_client.fileno())
                    remove_client.close()

    s.close()



if __name__ == '__main__':
    tcp_server()
